package cn.csg.iotplatform.module.system.controller.admin.permission;

import cn.csg.iotplatform.framework.common.enums.CommonStatusEnum;
import cn.csg.iotplatform.framework.common.pojo.CommonResult;
import cn.csg.iotplatform.framework.common.util.collection.CollectionUtils;
import cn.csg.iotplatform.framework.common.util.object.BeanUtils;
import cn.csg.iotplatform.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.csg.iotplatform.framework.web.core.util.WebFrameworkUtils;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.menu.MenuRespVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.menu.MenuSimpleRespVO;
import cn.csg.iotplatform.module.system.convert.MenuConvert;
import cn.csg.iotplatform.module.system.convert.user.UserConvert;
import cn.csg.iotplatform.module.system.dal.dataobject.dept.DeptDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.MenuDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.RoleDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.UserRoleDO;
import cn.csg.iotplatform.module.system.dal.dataobject.user.AdminUserDO;
import cn.csg.iotplatform.module.system.dal.mysql.permission.MenuMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.RoleMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.UserRoleMapper;
import cn.csg.iotplatform.module.system.dal.mysql.user.AdminUserMapper;
import cn.csg.iotplatform.module.system.enums.user.UserIdEnum;
import cn.csg.iotplatform.module.system.service.permission.MenuService;
import cn.csg.iotplatform.module.system.service.permission.PermissionCheckService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.catalina.User;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

import static cn.csg.iotplatform.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csg.iotplatform.framework.common.pojo.CommonResult.success;
import static cn.csg.iotplatform.module.system.enums.ErrorCodeConstants.ROLE_NOT_EXISTS;
import static cn.csg.iotplatform.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;

@Tag(name = "管理后台 - 菜单")
@RestController
@RequestMapping("/system/menu")
@Validated
public class MenuController {

    @Resource
    private MenuService menuService;
    @Resource
    private AdminUserMapper adminUserMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private PermissionCheckService permissionCheckService;

    @PostMapping("/create")
    @Operation(summary = "创建菜单")
    @PreAuthorize("@ss.hasPermission('system:menu:create')")
    public CommonResult<Long> createMenu(@Valid @RequestBody MenuSaveVO createReqVO) {
        Long menuId = menuService.createMenu(createReqVO);
        return success(menuId);
    }

    @PutMapping("/update")
    @Operation(summary = "修改菜单")
    @PreAuthorize("@ss.hasPermission('system:menu:update')")
    public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) {
        menuService.updateMenu(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除菜单")
    @Parameter(name = "id", description = "角色编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('system:menu:delete')")
    public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) {
        menuService.deleteMenu(id);
        return success(true);
    }

    @GetMapping("/list")
    @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面")
    @PreAuthorize("@ss.hasPermission('system:menu:query')")
    public CommonResult<List<MenuRespVO>> getMenuList(MenuListReqVO reqVO) {
        List<MenuDO> list = menuService.getMenuList(reqVO);
        list.sort(Comparator.comparing(MenuDO::getSort));
        return success(BeanUtils.toBean(list, MenuRespVO.class));
    }

    public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() {
        List<MenuDO> list = menuService.getMenuListByTenant(new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
        list.sort(Comparator.comparing(MenuDO::getSort));

        Long userId = WebFrameworkUtils.getLoginUserId();
        List<MenuDO> userMenus = this.menuService.getUserMenuIds(userId);

        List<MenuSimpleRespVO> resultVos = MenuConvert.INSTANCE.convertSimpleList(list, CollectionUtils.convertMap(userMenus, MenuDO::getId));

        return success(resultVos);
    }

    @GetMapping({"/list-all-simple", "simple-list"})
    @Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单，用于【角色分配菜单】功能的选项。" +
            "在多租户的场景下，会只返回租户所在套餐有的菜单")
    public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuListV2(@RequestParam(name = "roleId", required = false) String roleId) {
        Long userId = WebFrameworkUtils.getLoginUserId();
        AdminUserDO adminUserDO = adminUserMapper.selectById(userId);
        if (adminUserDO == null){
            throw exception(USER_NOT_EXISTS);
        }

        //判断是否为超管角色
        LambdaQueryWrapper<UserRoleDO> queryUserRoleWrapper = new LambdaQueryWrapper<UserRoleDO>().eq(UserRoleDO::getUserId, userId);
        List<UserRoleDO> userRoleDOS = userRoleMapper.selectList(queryUserRoleWrapper);
        boolean isSuperAdmin = userId != null && userId == UserIdEnum.SUPERADMIN.getUserId();
        if(isSuperAdmin){
            //直接查询所有的菜单
            LambdaQueryWrapper<MenuDO> querySuperAdminMenuWrapper = new LambdaQueryWrapper<MenuDO>()
                    .eq(MenuDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                    .orderByAsc(MenuDO::getSort);
            List<MenuDO> menuDOS = menuMapper.selectList(querySuperAdminMenuWrapper);
            List<MenuSimpleRespVO> menuSimpleRespVOS = menuDOS.stream().map(v -> {
                MenuSimpleRespVO menuSimpleRespVO = new MenuSimpleRespVO();
                menuSimpleRespVO.setId(v.getId());
                menuSimpleRespVO.setName(v.getName());
                menuSimpleRespVO.setParentId(v.getParentId());
                menuSimpleRespVO.setType(v.getType());
                menuSimpleRespVO.setIsGray(0);
                return menuSimpleRespVO;
            }).collect(Collectors.toList());
            return success(menuSimpleRespVOS);
        }

        //判断当前用户角色
        List<Long> userRoleIds = userRoleDOS.stream().map(UserRoleDO::getRoleId).collect(Collectors.toList());
        if (userRoleIds.isEmpty()){
            return success(new ArrayList<>());
        }

        //判断当前角色是否是当前用户创建
        boolean isCurrentUserCreate = false;
        if (StrUtil.isNotBlank(roleId)){
            RoleDO roleDO = roleMapper.selectById(roleId);
            if (roleDO != null && !userId.equals(roleDO.getCreator())){
                //非当前用户创建角色，返回当前角色所有菜单权限
                isCurrentUserCreate = true;
            }
        }

        //判断当前用户角色拥有的菜单权限
        LambdaQueryWrapper<RoleMenuDO> queryRoleMenuWrapper = new LambdaQueryWrapper<RoleMenuDO>()
                .in(RoleMenuDO::getRoleId, isCurrentUserCreate ? userRoleIds : Collections.singletonList(roleId));
        List<RoleMenuDO> roleMenuDOS = roleMenuMapper.selectList(queryRoleMenuWrapper);
        List<Long> userMenuIds = roleMenuDOS.stream().map(RoleMenuDO::getMenuId).collect(Collectors.toList());
        if (userMenuIds.isEmpty()){
            return success(new ArrayList<>());
        }

        //组装显示可用的菜单权限
        LambdaQueryWrapper<MenuDO> queryMenuWrapper = new LambdaQueryWrapper<MenuDO>()
                .eq(MenuDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .in(MenuDO::getId, userMenuIds)
                .orderByAsc(MenuDO::getSort);
        List<MenuDO> menuDOList = menuMapper.selectList(queryMenuWrapper);
        List<MenuSimpleRespVO> menuSimpleRespVOS = menuDOList.stream().map(v -> {
            MenuSimpleRespVO menuSimpleRespVO = new MenuSimpleRespVO();
            menuSimpleRespVO.setId(v.getId());
            menuSimpleRespVO.setName(v.getName());
            menuSimpleRespVO.setParentId(v.getParentId());
            menuSimpleRespVO.setType(v.getType());
            menuSimpleRespVO.setIsGray(0);
            return menuSimpleRespVO;
        }).collect(Collectors.toList());

        return success(menuSimpleRespVOS);
    }

    @GetMapping("/get")
    @Operation(summary = "获取菜单信息")
    @PreAuthorize("@ss.hasPermission('system:menu:query')")
    public CommonResult<MenuRespVO> getMenu(Long id) {
        MenuDO menu = menuService.getMenu(id);
        return success(BeanUtils.toBean(menu, MenuRespVO.class));
    }

    @PostMapping("/permission-check")
    @PreAuthorize("@ss.hasPermission('system:menu:update')")
    public CommonResult<Boolean> checkMenu(@RequestParam("parentId") Long parentId,@RequestParam("namePrefix") String namePrefix,@RequestParam("className") String className) {
        permissionCheckService.checkPerimissions(parentId,namePrefix,className);
        return success(true);
    }

}
